package com.junxonline.instant.admin.handler;

import com.junxonline.instant.common.entity.common.CommonResult;
import com.junxonline.instant.common.enumeration.AdminErrorEnum;
import com.junxonline.instant.common.exception.AdminBizException;
import lombok.extern.log4j.Log4j2;
import org.apache.dubbo.rpc.RpcException;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

/**
 * 管理后台异常处理
 *
 * @author JunX
 * @date 2021-06-25
 */
@Log4j2
@ControllerAdvice
@RestController
public class AdminBizExceptionHandler {

    /**
     * Shiro(UnauthenticatedException)异常
     * 该异常为以游客身份访问有权限管控的请求无法对匿名主体进行授权，而授权失败所抛出的异常
     * 不处理该异常
     *
     * @param e e
     */
    @ExceptionHandler(value = UnauthenticatedException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public CommonResult UnauthenticatedException(UnauthenticatedException e) {
        log.error("未登录无法执行鉴权 => {}", e.getMessage());
        return CommonResult.fail(AdminErrorEnum.AUTH_FAIL);
    }

    /**
     * Shiro(UnauthorizedException)异常 该异常为访问有权限管控的请求而该用户没有所需权限所抛出的异常
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = UnauthorizedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public CommonResult UnauthorizedException(UnauthorizedException e) {
        log.error("鉴权失败 => {}", e.getMessage());
        return CommonResult.fail(AdminErrorEnum.PERMISSION_FAIL);
    }

    /**
     * 捕捉所有Shiro异常
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = ShiroException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public CommonResult ShiroException(ShiroException e) {
        log.error("认证失败 => {}", e.getMessage());
        return CommonResult.fail(AdminErrorEnum.AUTH_FAIL);
    }

    /**
     * 请求类型异常处理
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CommonResult httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        log.error("请求发生异常 => {}", e.getMethod());
        return CommonResult.fail(AdminErrorEnum.REQUEST_TYPE_NOT_SUPPORT);
    }

    /**
     * 断言异常处理
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CommonResult illegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error("系统发生断言异常 => ", e);
        return CommonResult.fail(AdminErrorEnum.INTERNAL_SERVER_ERROR.getCode(), e.getMessage());
    }

    /**
     * RPC异常处理
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = RpcException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CommonResult illegalArgumentExceptionHandler(RpcException e) {
        log.error("RPC服务连接失败 => ", e);
        return CommonResult.fail(AdminErrorEnum.RPC_SERVICE_ERROR);
    }



    /**
     * 业务异常处理
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = AdminBizException.class)
    public CommonResult adminBizExceptionHandler(AdminBizException e) {
        log.error("系统发生业务异常 => {}", e.getMsg());
        return CommonResult.fail(e.getCode(), e.getMsg());
    }

    /**
     * 其它异常处理
     *
     * @param e e
     * @return CommonResult
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CommonResult exceptionHandler(Exception e) {
        log.error("系统发生异常 => ", e);
        return CommonResult.fail(AdminErrorEnum.INTERNAL_SERVER_ERROR);
    }

}
